#pragma once

#include <string>
#include <unordered_set>
#include <fstream>
#include <stdio.h>
#include <cstring>

#include "log.hpp"

#define SAFECMD_PATH "./safecmd.txt"

class doCmd
{
private:
    // 将白名单中的命令放入set中
    void logSafeCmd()
    {
        std::ifstream in;
        in.open(_safe_cmd_path, std::ifstream::in);
        if (!in.is_open())
        {
            LOG(FATA, "open error");
            exit(1);
        }

        std::string cmd;
        while (std::getline(in, cmd))
        {
            _safe_cmd.insert(cmd);

            LOG(DEBUG, "%s log success", cmd.c_str());
        }
    }

    bool isSafe(const std::string& cmd)
    {
        int pos = cmd.find(" ");
        std::string prev = cmd.substr(0, pos);

        auto iter = _safe_cmd.find(prev);
        if (iter == _safe_cmd.end())
            return false;

        return true;
    }

public:
    doCmd(const std::string safe_cmd_path = SAFECMD_PATH)
        : _safe_cmd_path(safe_cmd_path)
    {
        logSafeCmd();
    }

    std::string execute(const std::string& cmd)
    {
        if (!isSafe(cmd))
            return "坏人";
        
        FILE* cmd_ret = popen(cmd.c_str(), "r");
        if (cmd_ret == nullptr)
        {
            LOG(FATA, "popen error");
            exit(1);
        }

        std::string ret;
        char buffer[1024]{0};
        while (fgets(buffer, sizeof(buffer) - 1, cmd_ret))
        {
            ret += buffer;
            memset(buffer, 0, sizeof(buffer));
        }

        return ret.size() == 0 ? "null" : ret;
    }

private:
    std::string _safe_cmd_path;
    std::unordered_set<std::string> _safe_cmd;
};